package com.middlegroup.subjectpay.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.middlegroup.common.enums.ConfigKeyEnums;
import com.middlegroup.common.exception.ErrorMsg;
import com.middlegroup.common.model.NotifyRequest;
import com.middlegroup.common.model.SubjectpayQueryRequest;
import com.middlegroup.common.model.TransResult;
import com.middlegroup.common.utils.DateUtils;
import com.middlegroup.subjectpay.dto.TransRequest;
import com.middlegroup.subjectpay.entity.*;
import com.middlegroup.subjectpay.service.*;
import com.middlegroup.subjectpay.service.changpay.BaseConstant;
import com.middlegroup.subjectpay.service.changpay.ChanPayUtil;
import com.middlegroup.subjectpay.service.changpay.ChangpayCallbackRequest;
import com.middlegroup.subjectpay.service.changpay.RSA;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 *
 * @author pc
 * @date 2019/1/23
 */
@Service
@Slf4j
public class ChangpayServiceImpl implements ChangpayService {
    @Resource
    private RestTemplate restTemplate;
    @Resource
    private ChangpayBankNameService changpayBankNameService;
    @Resource
    private SubjectChannelConfigService subjectChannelConfigService;
    @Resource
    private SubjectOutThirdBillsService subjectOutThirdBillsService;
    @Resource
    private SubjectOutNotifyLogService subjectOutNotifyLogService;
    @Resource
    private SubjectOutBillsService subjectOutBillsService;
    @Resource
    private SubjectPayNotifyUtil subjectPayNotifyUtil;
    @Resource
    private SubjectInThirdBillsService subjectInThirdBillsService;
    @Resource
    private SubjectInNotifyLogService subjectInNotifyLogService;
    @Resource
    private SubjectInBillsService subjectInBillsService;
    @Resource
    private ThirdProtocolBindCardService thirdProtocolBindCardService;
    @Resource
    private BindCardService bindCardService;

    @Override
    public TransResult df(TransRequest request) {
        TransResult transResult = new TransResult();
        transResult.setBillNo(request.getBillNo());
        transResult.setMerchantBillNo(request.getMerchantBillNo());
        transResult.setAmount(request.getAmount());
        transResult.setTransStatus(0);
        transResult.setTransTime(System.currentTimeMillis());

        ChangpayBankName changpayBankName = changpayBankNameService.getBankName(request.getCardBin());
        if (null == changpayBankName || StringUtils.isBlank(changpayBankName.getChangpayBankName())){
            transResult.setTransStatus(2);
            transResult.setMsg(ErrorMsg.NONSUPPORT_BANK);
            return transResult;
        }

        String category=request.getChannelCode().getCode();

        String merchantNo=subjectChannelConfigService.getConfigString(category,ConfigKeyEnums.MERCHANTNO.getName());
        String requestUrl=subjectChannelConfigService.getConfigString(category,ConfigKeyEnums.REQUESTURL.getName());
        String privateKey=subjectChannelConfigService.getConfigString(category,ConfigKeyEnums.PRIVATEKEY.getName());
        String publicKey=subjectChannelConfigService.getConfigString(category,ConfigKeyEnums.PUBLICKEY.getName());
        String callBackUrl=subjectChannelConfigService.getConfigString(category,ConfigKeyEnums.CALLBACKURL.getName());
        String MD5Key=subjectChannelConfigService.getConfigString(category,ConfigKeyEnums.MD5KEY.getName());

//        String merchantNo="200001560076";
//        String requestUrl="https://pay.chanpay.com/mag-unify/gateway/receiveOrder.do";
//        String privateKey="MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAKSrtr+KNZz9AnTiTcJ7JWdZhx+WVFdP4hfOlHQJ7lTCS2zBiIo9a/JqnZojKlKC7lY7sEfazR/torpFREpi6LUP6+myDC5PreuMpvZpl5hegVGTqmrVCcB+D68yUFYcD+bibRFFKzzKkmUcyhS1DH/C6v+vtiCBVu7PFCNc211TAgMBAAECgYAXKA6K4OSpLusphKlqr+aSogRebMVvgcxJjMNTjhH12VzB7nVE+14yuMtw4YESGVdqyPoBIMO3ubMofpUb4MzYb5DM8s+RT47uVufKWIbOF8EQIoGXEh23g3C2XHA/JyeXajIM6gY9LrtzqgUXZ9Ngj9qkny9qBE3mxf7UnNxgAQJBANiPAAtA6uvQwwFMi0AP4661F/GAv7hWKcIuq6ukg80QgYYm0CsVPXouErmchgJDQMBCYVd+4PdbToFLdLXjadcCQQDCqXQ3x5fb23Bh2X61f4WdmVbeHWcCWKeXNL3T0iqMJMTdyg6LVOiCX8+RmfZW7liyyrdnqMU2pt/AS3+pKdDlAkBow914lEJSLN96DGa9ajJyvadErU2SxxRSnbNtSRx+I0MV/Ebu4MqqBgoHA4MNKy3zFOn0oywAXoq/IBrpN4hnAkEAvx5QFFPKLPmNpQQ8+0VwkgLy3rBPamZQZIxLs6QsUdvnzTmMfg+nGBmpWXKoAUGRpDiTSRrSRY4hMFLvy85aYQJAfrUP8xMeNQ6iRT1KWAeBX6QDHCZLiBoM5+ug2PCcL4B79FFvRR2wArlzdXb9fiMqOnQZLDKU9z3dEvkVH6AZDQ==";
//        String publicKey="MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDPq3oXX5aFeBQGf3Ag/86zNu0VICXmkof85r+DDL46w3vHcTnkEWVbp9DaDurcF7DMctzJngO0u9OG1cb4mn+Pn/uNC1fp7S4JH4xtwST6jFgHtXcTG9uewWFYWKw/8b3zf4fXyRuI/2ekeLSstftqnMQdenVP7XCxMuEnnmM1RwIDAQAB";
//        String callBackUrl="https://api.yihuabao.cn/yhb/api/1.0.0/notify/changpayDfNotify";
//        String MD5Key="该渠道不用这个字段值";

        if(StringUtils.isBlank(requestUrl) || StringUtils.isBlank(merchantNo) || StringUtils.isBlank(privateKey) || StringUtils.isBlank(publicKey) || StringUtils.isBlank(callBackUrl) || StringUtils.isBlank(MD5Key)){
            transResult.setTransStatus(2);
            transResult.setMsg(ErrorMsg.INCOMPLETE_CONFIG_INFO);
            return transResult;
        }

        Map<String, String> map = this.requestBaseParameter("cjt_dsf",merchantNo);
        // 交易码
        map.put("TransCode", "T10000");
        // 商户网站唯一订单号
        map.put("OutTradeNo", request.getBillNo());
        // 0=私人，1=公司
        map.put("BusinessType", "0");
        // 通用银行名称
        map.put("BankCommonName", changpayBankName.getChangpayBankName());
        // 收款方银行卡或存折号码。使用平台公钥加密。
        map.put("AcctNo", ChanPayUtil.encrypt(request.getCardNo(),publicKey, BaseConstant.CHARSET));
        // 收款方银行卡或存折上的所有人姓名。使用平台公钥加密。
        map.put("AcctName", ChanPayUtil.encrypt(request.getName(), publicKey, BaseConstant.CHARSET));
        map.put("TransAmt", request.getAmount().toString());
        //商户提供的推送url地址。
        map.put("CorpPushUrl",callBackUrl);
        //账号类型 00：借记卡
        map.put("AccountType", "00");
        //货币类型
        map.put("Currency", "CNY");
        //证件类型 01身份证
        map.put("LiceneceType", "01");
        map.put("PostScript", "用途：放款");

        SubjectOutThirdBills subjectOutThirdBills=new SubjectOutThirdBills();
        subjectOutThirdBills.setSubjectCode(request.getSubjectCode());
        subjectOutThirdBills.setMerchantBillNo(request.getMerchantBillNo());
        subjectOutThirdBills.setBillNo(request.getBillNo());
        subjectOutThirdBills.setStatus(0);
        subjectOutThirdBills.setAmount(request.getAmount());
        subjectOutThirdBills.setRequestUrl(requestUrl);
        subjectOutThirdBills.setRequestText(JSON.toJSONString(map));
        subjectOutThirdBills.setBeginTime(System.currentTimeMillis());
        subjectOutThirdBills.setServiceType(request.getServiceType());

        MultiValueMap<String, String> postParameters = new LinkedMultiValueMap<String, String>();
        try {
            Map<String, String> param = ChanPayUtil.buildRequestPara(map,"RSA", privateKey, BaseConstant.CHARSET);
            for(String key : param.keySet()) {
                String value = URLEncoder.encode(param.get(key), BaseConstant.CHARSET);
                postParameters.add(key, value);
            }
        } catch (Exception e) {
            log.error("畅捷代付请求数据加密失败,billNo:{},error:{}",request.getBillNo(),e);
            transResult.setTransStatus(2);
            transResult.setMsg(ErrorMsg.DATA_ENCRYPTION_FAIL);
            return transResult;
        }

        String str = null;
        try {
            str = restTemplate.postForObject(requestUrl,postParameters,String.class);
        } catch (Exception e) {
            log.error("调用畅捷支付代付接口异常,billNo:{},error:{}",request.getBillNo(),e);
            transResult.setMsg(ErrorMsg.PAY_INTERFACE_CALL_FAIL);
        }

        subjectOutThirdBills.setResponseText((StringUtils.isNotBlank(str) && str.length()>4000)?str.substring(0,4000):str);
        subjectOutThirdBills.setEndTime(System.currentTimeMillis());

        if (StringUtils.isBlank(str)) {
            //默认交易处理中
            log.error("调用畅捷支付代付接口返回空,billNo:{}",request.getBillNo());
            transResult.setMsg(ErrorMsg.PAY_INTERFACE_RETURN_BLANK);
        }else {
            JSONObject jsonObjectStr = JSONObject.parseObject(str);
            if(null != jsonObjectStr){
                //签名
                String sign=jsonObjectStr.getString("Sign");
                String sign2=null;
                boolean verifyResult=false;
                try {
                    Map<String,String> maps = (Map) JSON.parse(str);
                    sign2=ChanPayUtil.createLinkString(maps,false);
                    verifyResult= RSA.verify(sign2,sign,publicKey,BaseConstant.CHARSET);
                } catch (Exception e) {
                    transResult.setMsg(ErrorMsg.RETURN_DATA_CHECK_SIGN_FAIL);
                    log.error("畅捷支付代付返回数据签名出错,str:{},error:{}",str,e);
                }
                if(verifyResult){
                    //请求状态
                    String acceptStatus=jsonObjectStr.getString("AcceptStatus");
                    //平台状态
                    String platformRetCode=jsonObjectStr.getString("PlatformRetCode");
                    //平台返回错误信息
                    String platformErrorMessage=jsonObjectStr.getString("PlatformErrorMessage");
                    //交易状态
                    String originalRetCode=jsonObjectStr.getString("OriginalRetCode");
                    //原交易错误信息描述
                    String originalErrorMessage=jsonObjectStr.getString("OriginalErrorMessage");
                    //交易流水号
                    String flowNo=jsonObjectStr.getString("FlowNo");

                    transResult.setTransNo(flowNo);
                    transResult.setMsg(originalErrorMessage);

                    if (StringUtils.equals(acceptStatus,"S") && StringUtils.equals(platformRetCode,"0000")) {
                        if(StringUtils.equals(originalRetCode,"000000")){
                            //交易成功
                            transResult.setTransTime(System.currentTimeMillis());
                            transResult.setTransStatus(1);
                            subjectOutThirdBills.setStatus(1);
                        } else if(StringUtils.equals(originalRetCode,"111111")){
                            //交易失败
                            transResult.setTransStatus(2);
                            subjectOutThirdBills.setStatus(2);
                        }else {
                            //未知状态
                            transResult.setTransStatus(0);
                            subjectOutThirdBills.setStatus(0);
                        }
                    } else {
                        transResult.setTransStatus(0);
                        subjectOutThirdBills.setStatus(0);
                        transResult.setMsg(platformErrorMessage);
                    }
                }else {
                    transResult.setMsg(ErrorMsg.RETURN_DATA_CHECK_SIGN_FAIL);
                }
            }else {
                transResult.setMsg(ErrorMsg.PAY_INTERFACE_RETURN_BLANK);
            }
        }

        try {
            subjectOutThirdBillsService.insert(subjectOutThirdBills);
        } catch (Exception e) {
            log.error("畅捷代付插入第三方订单表异常,billNo:{},error:{}",request.getBillNo(),e);
        }

        return transResult;
    }

    @Override
    public TransResult dfQuery(SubjectpayQueryRequest request) {
        TransResult transResult = new TransResult();
        transResult.setBillNo(request.getBillNo());
        transResult.setMerchantBillNo(request.getMerchantBillNo());
        transResult.setAmount(request.getAmount());
        transResult.setTransStatus(0);
        transResult.setTransTime(System.currentTimeMillis());

        String category=request.getChannelCode();

        String merchantNo=subjectChannelConfigService.getConfigString(category,ConfigKeyEnums.MERCHANTNO.getName());
        String requestUrl=subjectChannelConfigService.getConfigString(category,ConfigKeyEnums.REQUESTURL.getName());
        String privateKey=subjectChannelConfigService.getConfigString(category,ConfigKeyEnums.PRIVATEKEY.getName());
        String publicKey=subjectChannelConfigService.getConfigString(category,ConfigKeyEnums.PUBLICKEY.getName());
        String callBackUrl=subjectChannelConfigService.getConfigString(category,ConfigKeyEnums.CALLBACKURL.getName());
        String MD5Key=subjectChannelConfigService.getConfigString(category,ConfigKeyEnums.MD5KEY.getName());

        if(StringUtils.isBlank(requestUrl) || StringUtils.isBlank(merchantNo) || StringUtils.isBlank(privateKey) || StringUtils.isBlank(publicKey) || StringUtils.isBlank(callBackUrl) || StringUtils.isBlank(MD5Key)){
            transResult.setTransStatus(2);
            transResult.setMsg(ErrorMsg.INCOMPLETE_CONFIG_INFO);
            return transResult;
        }

        Map<String, String> map = this.requestBaseParameter("cjt_dsf",merchantNo);
        // 交易码
        map.put("TransCode", "C00000");
        // 原交易请求号
        map.put("OriOutTradeNo", request.getBillNo());
        String OutTradeNo = UUID.randomUUID().toString().replaceAll("-","");
        // 交易请求号
        map.put("OutTradeNo",OutTradeNo);

        SubjectOutThirdBills subjectOutThirdBills=new SubjectOutThirdBills();
        subjectOutThirdBills.setSubjectCode(request.getSubjectCode());
        subjectOutThirdBills.setMerchantBillNo(request.getMerchantBillNo());
        subjectOutThirdBills.setBillNo(request.getBillNo());
        subjectOutThirdBills.setStatus(0);
        subjectOutThirdBills.setAmount(request.getAmount());
        subjectOutThirdBills.setRequestUrl(requestUrl);
        subjectOutThirdBills.setRequestText(JSON.toJSONString(map));
        subjectOutThirdBills.setBeginTime(System.currentTimeMillis());
        subjectOutThirdBills.setServiceType(request.getServiceType());

        MultiValueMap<String, String> postParameters = new LinkedMultiValueMap<String, String>();
        try {
            Map<String, String> param = ChanPayUtil.buildRequestPara(map,"RSA", privateKey, BaseConstant.CHARSET);
            for(String key : param.keySet()) {
                String value = URLEncoder.encode(param.get(key), BaseConstant.CHARSET);
                postParameters.add(key, value);
            }
        } catch (Exception e) {
            log.error("畅捷代付查询请求数据加密失败,billNo:{},error:{}",request.getBillNo(),e);
            transResult.setTransStatus(2);
            transResult.setMsg(ErrorMsg.DATA_ENCRYPTION_FAIL);
            return transResult;
        }

        String str = null;
        try {
            str = restTemplate.postForObject(requestUrl,postParameters,String.class);
        } catch (Exception e) {
            log.error("调用畅捷支付代付查询接口异常,billNo:{},error:{}",request.getBillNo(),e);
            transResult.setMsg(ErrorMsg.PAY_INTERFACE_CALL_FAIL);
        }

        subjectOutThirdBills.setResponseText((StringUtils.isNotBlank(str) && str.length()>4000)?str.substring(0,4000):str);
        subjectOutThirdBills.setEndTime(System.currentTimeMillis());

        if (StringUtils.isBlank(str)) {
            //默认交易处理中
            log.error("调用畅捷支付代付查询接口返回空,billNo:{}",request.getBillNo());
            transResult.setMsg(ErrorMsg.PAY_INTERFACE_RETURN_BLANK);
        }else {
            JSONObject jsonObjectStr = JSONObject.parseObject(str);
            if(null != jsonObjectStr){
                //签名
                String sign=jsonObjectStr.getString("Sign");
                String sign2=null;
                boolean verifyResult=false;
                try {
                    Map<String,String> maps = (Map) JSON.parse(str);
                    sign2=ChanPayUtil.createLinkString(maps,false);
                    verifyResult= RSA.verify(sign2,sign,publicKey,BaseConstant.CHARSET);
                } catch (Exception e) {
                    transResult.setMsg(ErrorMsg.RETURN_DATA_CHECK_SIGN_FAIL);
                    log.error("畅捷支付代付查询返回数据签名出错,str:{},error:{}",str,e);
                }
                if(verifyResult){
                    //请求状态
                    String acceptStatus=jsonObjectStr.getString("AcceptStatus");
                    //平台状态
                    String platformRetCode=jsonObjectStr.getString("PlatformRetCode");
                    //平台返回错误信息
                    String platformErrorMessage=jsonObjectStr.getString("PlatformErrorMessage");
                    //交易状态
                    String originalRetCode=jsonObjectStr.getString("OriginalRetCode");
                    //原交易错误信息描述
                    String originalErrorMessage=jsonObjectStr.getString("OriginalErrorMessage");
                    //交易流水号
                    String flowNo=jsonObjectStr.getString("FlowNo");

                    transResult.setTransNo(flowNo);
                    transResult.setMsg(originalErrorMessage);

                    if (StringUtils.equals(acceptStatus,"S") && StringUtils.equals(platformRetCode,"0000")) {
                        if(StringUtils.equals(originalRetCode,"000000")){
                            //交易成功
                            transResult.setTransTime(System.currentTimeMillis());
                            transResult.setTransStatus(1);
                            subjectOutThirdBills.setStatus(1);
                        } else if(StringUtils.equals(originalRetCode,"111111")){
                            //交易失败
                            transResult.setTransStatus(2);
                            subjectOutThirdBills.setStatus(2);
                        }else {
                            //未知状态
                            transResult.setTransStatus(0);
                            subjectOutThirdBills.setStatus(0);
                        }
                    } else {
                        transResult.setMsg(platformErrorMessage);
                        if(StringUtils.equals(platformRetCode,"2004") || StringUtils.equals(platformRetCode,"2009")){
                            subjectOutThirdBills.setStatus(2);
                            transResult.setTransStatus(2);
                        }
                    }
                }else {
                    transResult.setMsg(ErrorMsg.RETURN_DATA_CHECK_SIGN_FAIL);
                }
            }else {
                transResult.setMsg(ErrorMsg.PAY_INTERFACE_RETURN_BLANK);
            }
        }

        try {
            subjectOutThirdBillsService.insert(subjectOutThirdBills);
        } catch (Exception e) {
            log.error("畅捷代付插入第三方订单表异常,billNo:{},error:{}",request.getBillNo(),e);
        }

        return transResult;
    }

    @Override
    public String dfNotify(ChangpayCallbackRequest request) {
        String result ="";

        //记录回调原始数据
        SubjectOutNotifyLog subjectOutNotifyLog = new SubjectOutNotifyLog();
        subjectOutNotifyLog.setBillNo(request.getOuter_trade_no());
        subjectOutNotifyLog.setCallbackText(JSONObject.toJSONString(request));
        //默认回调处理状态为处理中
        subjectOutNotifyLog.setStatus(0);
        //默认订单交易状态为处理中
        subjectOutNotifyLog.setTransStatus(0);
        subjectOutNotifyLog.setCallbackText(JSONObject.toJSONString(request));
        subjectOutNotifyLog.setMsg("回调处理中");
        boolean rt = subjectOutNotifyLogService.insert(subjectOutNotifyLog);
        if (!rt){
            log.error("插入回调日志表失败,request:{}",request);
            return result;
        }

        //查询回调对应的订单信息
        SubjectOutBills subjectOutBillsFind = new SubjectOutBills();
        subjectOutBillsFind.setBillNo(request.getOuter_trade_no());
        SubjectOutBills subjectOutBills = subjectOutBillsService.getLastOneOutBills(subjectOutBillsFind);
        if(null==subjectOutBills){
            log.error("未查询到该笔订单,request:{}",request);
            return result;
        }
        subjectOutNotifyLog.setSubjectCode(subjectOutBills.getSubjectCode());
        subjectOutNotifyLog.setMerchantBillNo(subjectOutBills.getMerchantBillNo());

        //转发到支付中台的回调对象
        NotifyRequest notifyRequest=new NotifyRequest();
        notifyRequest.setMerchantBillNo(subjectOutBills.getMerchantBillNo());
        notifyRequest.setBillNo(subjectOutBills.getBillNo());
        notifyRequest.setTransStatus(0);
        notifyRequest.setMsg("回调处理中");
        notifyRequest.setTransTime(System.currentTimeMillis());
        notifyRequest.setAmount(subjectOutBills.getAmount());

        String category=subjectOutBills.getChannelCode();
        String publicKey=subjectChannelConfigService.getConfigString(category,ConfigKeyEnums.PUBLICKEY.getName());

        boolean verifyResult = false;
        if(null!=request){
            //签名
            String sign=request.getSign();
            String sign2=null;
            try {
                Map<String,String> maps = (Map) JSON.parse(subjectOutNotifyLog.getCallbackText());
                maps = ChanPayUtil.paraFilter(maps);
                if(!maps.containsKey("_input_charset")){
                    maps.put("_input_charset","UTF-8");
                }
                sign2= ChanPayUtil.createLinkString(maps,false);
                verifyResult=RSA.verify(sign2,sign,publicKey, BaseConstant.CHARSET);
            } catch (Exception e) {
                log.error("畅捷支付代付回调返回数据签名出错,request:{},error:{}",request,e);
            }

            if(verifyResult){
                String transNo=request.getInner_trade_no();
                //WITHDRAWAL_SUCCESS:成功  WITHDRAWAL_FAIL：失败 RETURN_TICKET：退票
                String status=request.getWithdrawal_status();
                //支付时间 要转换 yyyyMMddHHmmss
                String tradeTime=request.getGmt_withdrawal();
                //失败原因
                String fail_reason=request.getFail_reason();

                subjectOutNotifyLog.setStatus(1);
                subjectOutNotifyLog.setTransNo(transNo);
                subjectOutNotifyLog.setMsg(fail_reason);
                notifyRequest.setTransNo(transNo);
                notifyRequest.setMsg(fail_reason);

                if ((subjectOutBills.getStatus().intValue() == 0 || subjectOutBills.getStatus().intValue() == 3)){
                    if(StringUtils.isNotBlank(status)){
                        if(StringUtils.equals("WITHDRAWAL_SUCCESS",status)){
                            //支付成功
                            if(StringUtils.isNotBlank(tradeTime)){
                                Long time= DateUtils.convert(tradeTime,DateUtils.DATE_TIMESTAMP_SHORT_FORMAT).getTime();
                                notifyRequest.setTransTime(time);
                            }else{
                                notifyRequest.setTransTime(System.currentTimeMillis());
                            }

                            notifyRequest.setTransStatus(1);
                            subjectOutNotifyLog.setTransStatus(1);
                        }else if(StringUtils.equals("WITHDRAWAL_FAIL",status) || StringUtils.equals("RETURN_TICKET",status)){
                            //支付失败
                            notifyRequest.setTransStatus(2);
                            subjectOutNotifyLog.setTransStatus(2);
                        } else {
                            //支付处理中
                            notifyRequest.setTransStatus(0);
                            subjectOutNotifyLog.setTransStatus(0);
                        }
                    }else {
                        subjectOutNotifyLog.setMsg("没有交易状态");
                    }

                    int transStatus = notifyRequest.getTransStatus().intValue();
                    if (transStatus == 1 || transStatus == 2) {
                        //更新订单表状态
                        subjectOutBills.setStatus(transStatus);
                        subjectOutBillsService.updateById(subjectOutBills);
                        try {
                            //TODO 回调支付中台
                            subjectPayNotifyUtil.notifyPay(subjectOutBills.getSubjectCode(),"notify/df",notifyRequest);
                        }catch (Exception e){
                            log.error("回调支付中台异常，notifyRequest：{},error：{}",notifyRequest,e);
                        }
                    }
                }else {
                    subjectOutNotifyLog.setMsg("订单状态已确定,不处理");
                }
                result ="success";
            }else {
                //验签不通过
                //直接返回不处理业务
                subjectOutNotifyLog.setStatus(2);
                subjectOutNotifyLog.setMsg("畅捷支付回调_验签不通过");
                log.error("畅捷支付回调_验签失败,request:{}",request);
            }

        }

        //记录通知第三方支付公司的信息
        subjectOutNotifyLog.setResponseText(result);
        try {
            subjectOutNotifyLogService.updateById(subjectOutNotifyLog);
        }catch (Exception e){
            log.error("更新支付回调记录表失败,request:{},error:{}",request,e);
        }
        return result;
    }

    @Override
    public TransResult deduct(TransRequest request) {
        TransResult transResult = new TransResult();
        transResult.setBillNo(request.getBillNo());
        transResult.setMerchantBillNo(request.getMerchantBillNo());
        transResult.setAmount(request.getAmount());
        transResult.setTransStatus(0);
        transResult.setTransTime(System.currentTimeMillis());

        ChangpayBankName changpayBankName = changpayBankNameService.getBankName(request.getCardBin());
        if (null == changpayBankName || StringUtils.isBlank(changpayBankName.getChangpayBankName())){
            transResult.setTransStatus(2);
            transResult.setMsg(ErrorMsg.NONSUPPORT_BANK);
            return transResult;
        }

        String category=request.getChannelCode().getCode();

        String merchantNo=subjectChannelConfigService.getConfigString(category,ConfigKeyEnums.MERCHANTNO.getName());
        String requestUrl=subjectChannelConfigService.getConfigString(category,ConfigKeyEnums.REQUESTURL.getName());
        String privateKey=subjectChannelConfigService.getConfigString(category,ConfigKeyEnums.PRIVATEKEY.getName());
        String publicKey=subjectChannelConfigService.getConfigString(category,ConfigKeyEnums.PUBLICKEY.getName());
        String callBackUrl=subjectChannelConfigService.getConfigString(category,ConfigKeyEnums.CALLBACKURL.getName());
        String MD5Key=subjectChannelConfigService.getConfigString(category,ConfigKeyEnums.MD5KEY.getName());

        if(StringUtils.isBlank(requestUrl) || StringUtils.isBlank(merchantNo) || StringUtils.isBlank(privateKey) || StringUtils.isBlank(publicKey) || StringUtils.isBlank(callBackUrl) || StringUtils.isBlank(MD5Key)){
            transResult.setTransStatus(2);
            transResult.setMsg(ErrorMsg.INCOMPLETE_CONFIG_INFO);
            return transResult;
        }

        Map<String, String> map = this.requestBaseParameter("cjt_dsf",merchantNo);
        // 交易码
        map.put("TransCode", "T20000");
        // 商户网站唯一订单号
        map.put("OutTradeNo", request.getBillNo());
        // 0=私人，1=公司
        map.put("BusinessType", "0");
        // 通用银行名称
        map.put("BankCommonName", changpayBankName.getChangpayBankName());
        // 收款方银行卡或存折号码。使用平台公钥加密。
        map.put("AcctNo", ChanPayUtil.encrypt(request.getCardNo(),publicKey, BaseConstant.CHARSET));
        // 收款方银行卡或存折上的所有人姓名。使用平台公钥加密。
        map.put("AcctName", ChanPayUtil.encrypt(request.getName(), publicKey, BaseConstant.CHARSET));
        map.put("TransAmt", request.getAmount().toString());
        //商户提供的推送url地址。
        map.put("CorpPushUrl",callBackUrl);
        //账号类型 00：借记卡
        map.put("AccountType", "00");
        //货币类型
        map.put("Currency", "CNY");
        //证件类型 01身份证
        map.put("LiceneceType", "01");
        //身份证号
        map.put("LiceneceNo", ChanPayUtil.encrypt(request.getIdCard(), publicKey, BaseConstant.CHARSET));
        //手机号
        map.put("Phone", ChanPayUtil.encrypt(request.getPhone(), publicKey, BaseConstant.CHARSET));
        map.put("PostScript", "用途：代扣");

        SubjectInThirdBills subjectInThirdBills=new SubjectInThirdBills();
        subjectInThirdBills.setSubjectCode(request.getSubjectCode());
        subjectInThirdBills.setMerchantBillNo(request.getMerchantBillNo());
        subjectInThirdBills.setBillNo(request.getBillNo());
        subjectInThirdBills.setStatus(0);
        subjectInThirdBills.setAmount(request.getAmount());
        subjectInThirdBills.setRequestUrl(requestUrl);
        subjectInThirdBills.setRequestText(JSON.toJSONString(map));
        subjectInThirdBills.setBeginTime(System.currentTimeMillis());
        subjectInThirdBills.setServiceType(request.getServiceType());

        MultiValueMap<String, String> postParameters = new LinkedMultiValueMap<String, String>();
        try {
            Map<String, String> param = ChanPayUtil.buildRequestPara(map,"RSA", privateKey, BaseConstant.CHARSET);
            for(String key : param.keySet()) {
                String value = URLEncoder.encode(param.get(key), BaseConstant.CHARSET);
                postParameters.add(key, value);
            }
        } catch (Exception e) {
            log.error("畅捷代扣请求数据加密失败,billNo:{},error:{}",request.getBillNo(),e);
            transResult.setTransStatus(2);
            transResult.setMsg(ErrorMsg.DATA_ENCRYPTION_FAIL);
            return transResult;
        }

        String str = null;
        try {
            str = restTemplate.postForObject(requestUrl,postParameters,String.class);
        } catch (Exception e) {
            log.error("调用畅捷代扣接口异常,billNo:{},error:{}",request.getBillNo(),e);
            transResult.setMsg(ErrorMsg.PAY_INTERFACE_CALL_FAIL);
        }

        subjectInThirdBills.setResponseText((StringUtils.isNotBlank(str) && str.length()>4000)?str.substring(0,4000):str);
        subjectInThirdBills.setEndTime(System.currentTimeMillis());

        if (StringUtils.isBlank(str)) {
            //默认交易处理中
            log.error("调用畅捷代扣接口返回空,billNo:{}",request.getBillNo());
            transResult.setMsg(ErrorMsg.PAY_INTERFACE_RETURN_BLANK);
        }else {
            JSONObject jsonObjectStr = JSONObject.parseObject(str);
            if(null != jsonObjectStr){
                //签名
                String sign=jsonObjectStr.getString("Sign");
                String sign2=null;
                boolean verifyResult=false;
                try {
                    Map<String,String> maps = (Map) JSON.parse(str);
                    sign2=ChanPayUtil.createLinkString(maps,false);
                    verifyResult= RSA.verify(sign2,sign,publicKey,BaseConstant.CHARSET);
                } catch (Exception e) {
                    transResult.setMsg(ErrorMsg.RETURN_DATA_CHECK_SIGN_FAIL);
                    log.error("畅捷代扣返回数据签名出错,str:{},error:{}",str,e);
                }
                if(verifyResult){
                    //请求状态
                    String acceptStatus=jsonObjectStr.getString("AcceptStatus");
                    //平台状态
                    String platformRetCode=jsonObjectStr.getString("PlatformRetCode");
                    //平台返回错误信息
                    String platformErrorMessage=jsonObjectStr.getString("PlatformErrorMessage");
                    //交易状态
                    String originalRetCode=jsonObjectStr.getString("OriginalRetCode");
                    //原交易错误信息描述
                    String originalErrorMessage=jsonObjectStr.getString("OriginalErrorMessage");
                    //交易流水号
                    String flowNo=jsonObjectStr.getString("FlowNo");

                    transResult.setTransNo(flowNo);
                    transResult.setMsg(originalErrorMessage);

                    if (StringUtils.equals(acceptStatus,"S") && StringUtils.equals(platformRetCode,"0000")) {
                        if(StringUtils.equals(originalRetCode,"000000")){
                            //交易成功
                            transResult.setTransTime(System.currentTimeMillis());
                            transResult.setTransStatus(1);
                            subjectInThirdBills.setStatus(1);
                        } else if(StringUtils.equals(originalRetCode,"111111")){
                            //交易失败
                            transResult.setTransStatus(2);
                            subjectInThirdBills.setStatus(2);
                        }else {
                            //未知状态
                            transResult.setTransStatus(0);
                            subjectInThirdBills.setStatus(0);
                        }
                    } else {
                        transResult.setTransStatus(2);
                        subjectInThirdBills.setStatus(2);
                        transResult.setMsg(platformErrorMessage);
                    }
                }else {
                    transResult.setMsg(ErrorMsg.RETURN_DATA_CHECK_SIGN_FAIL);
                }
            }else {
                transResult.setMsg(ErrorMsg.PAY_INTERFACE_RETURN_BLANK);
            }
        }

        try {
            subjectInThirdBillsService.insert(subjectInThirdBills);
        } catch (Exception e) {
            log.error("畅捷代扣插入第三方订单表异常,billNo:{},error:{}",request.getBillNo(),e);
        }

        return transResult;
    }

    @Override
    public TransResult deductQuery(SubjectpayQueryRequest request) {
        TransResult transResult = new TransResult();
        transResult.setBillNo(request.getBillNo());
        transResult.setMerchantBillNo(request.getMerchantBillNo());
        transResult.setAmount(request.getAmount());
        transResult.setTransStatus(0);
        transResult.setTransTime(System.currentTimeMillis());

        String category=request.getChannelCode();

        String merchantNo=subjectChannelConfigService.getConfigString(category,ConfigKeyEnums.MERCHANTNO.getName());
        String requestUrl=subjectChannelConfigService.getConfigString(category,ConfigKeyEnums.REQUESTURL.getName());
        String privateKey=subjectChannelConfigService.getConfigString(category,ConfigKeyEnums.PRIVATEKEY.getName());
        String publicKey=subjectChannelConfigService.getConfigString(category,ConfigKeyEnums.PUBLICKEY.getName());
        String callBackUrl=subjectChannelConfigService.getConfigString(category,ConfigKeyEnums.CALLBACKURL.getName());
        String MD5Key=subjectChannelConfigService.getConfigString(category,ConfigKeyEnums.MD5KEY.getName());

        if(StringUtils.isBlank(requestUrl) || StringUtils.isBlank(merchantNo) || StringUtils.isBlank(privateKey) || StringUtils.isBlank(publicKey) || StringUtils.isBlank(callBackUrl) || StringUtils.isBlank(MD5Key)){
            transResult.setTransStatus(2);
            transResult.setMsg(ErrorMsg.INCOMPLETE_CONFIG_INFO);
            return transResult;
        }

        Map<String, String> map = this.requestBaseParameter("cjt_dsf",merchantNo);
        // 交易码
        map.put("TransCode", "C00000");
        // 原交易请求号
        map.put("OriOutTradeNo", request.getBillNo());
        String OutTradeNo = UUID.randomUUID().toString().replaceAll("-","");
        // 交易请求号
        map.put("OutTradeNo",OutTradeNo);

        SubjectInThirdBills subjectInThirdBills=new SubjectInThirdBills();
        subjectInThirdBills.setSubjectCode(request.getSubjectCode());
        subjectInThirdBills.setMerchantBillNo(request.getMerchantBillNo());
        subjectInThirdBills.setBillNo(request.getBillNo());
        subjectInThirdBills.setStatus(0);
        subjectInThirdBills.setAmount(request.getAmount());
        subjectInThirdBills.setRequestUrl(requestUrl);
        subjectInThirdBills.setRequestText(JSON.toJSONString(map));
        subjectInThirdBills.setBeginTime(System.currentTimeMillis());
        subjectInThirdBills.setServiceType(request.getServiceType());

        MultiValueMap<String, String> postParameters = new LinkedMultiValueMap<String, String>();
        try {
            Map<String, String> param = ChanPayUtil.buildRequestPara(map,"RSA", privateKey, BaseConstant.CHARSET);
            for(String key : param.keySet()) {
                String value = URLEncoder.encode(param.get(key), BaseConstant.CHARSET);
                postParameters.add(key, value);
            }
        } catch (Exception e) {
            log.error("畅捷代扣查询请求数据加密失败,billNo:{},error:{}",request.getBillNo(),e);
            transResult.setTransStatus(2);
            transResult.setMsg(ErrorMsg.DATA_ENCRYPTION_FAIL);
            return transResult;
        }

        String str = null;
        try {
            str = restTemplate.postForObject(requestUrl,postParameters,String.class);
        } catch (Exception e) {
            log.error("调用畅捷代扣查询接口异常,billNo:{},error:{}",request.getBillNo(),e);
            transResult.setMsg(ErrorMsg.PAY_INTERFACE_CALL_FAIL);
        }

        subjectInThirdBills.setResponseText((StringUtils.isNotBlank(str) && str.length()>4000)?str.substring(0,4000):str);
        subjectInThirdBills.setEndTime(System.currentTimeMillis());

        if (StringUtils.isBlank(str)) {
            //默认交易处理中
            log.error("调用畅捷支付代扣查询接口返回空,billNo:{}",request.getBillNo());
            transResult.setMsg(ErrorMsg.PAY_INTERFACE_RETURN_BLANK);
        }else {
            JSONObject jsonObjectStr = JSONObject.parseObject(str);
            if(null != jsonObjectStr){
                //签名
                String sign=jsonObjectStr.getString("Sign");
                String sign2=null;
                boolean verifyResult=false;
                try {
                    Map<String,String> maps = (Map) JSON.parse(str);
                    sign2=ChanPayUtil.createLinkString(maps,false);
                    verifyResult= RSA.verify(sign2,sign,publicKey,BaseConstant.CHARSET);
                } catch (Exception e) {
                    transResult.setMsg(ErrorMsg.RETURN_DATA_CHECK_SIGN_FAIL);
                    log.error("畅捷支付代扣查询返回数据签名出错,str:{},error:{}",str,e);
                }
                if(verifyResult){
                    //请求状态
                    String acceptStatus=jsonObjectStr.getString("AcceptStatus");
                    //平台状态
                    String platformRetCode=jsonObjectStr.getString("PlatformRetCode");
                    //平台返回错误信息
                    String platformErrorMessage=jsonObjectStr.getString("PlatformErrorMessage");
                    //交易状态
                    String originalRetCode=jsonObjectStr.getString("OriginalRetCode");
                    //原交易错误信息描述
                    String originalErrorMessage=jsonObjectStr.getString("OriginalErrorMessage");
                    //交易流水号
                    String flowNo=jsonObjectStr.getString("FlowNo");

                    transResult.setTransNo(flowNo);
                    transResult.setMsg(originalErrorMessage);

                    if (StringUtils.equals(acceptStatus,"S") && StringUtils.equals(platformRetCode,"0000")) {
                        if(StringUtils.equals(originalRetCode,"000000")){
                            //交易成功
                            transResult.setTransTime(System.currentTimeMillis());
                            transResult.setTransStatus(1);
                            subjectInThirdBills.setStatus(1);
                        } else if(StringUtils.equals(originalRetCode,"111111")){
                            //交易失败
                            transResult.setTransStatus(2);
                            subjectInThirdBills.setStatus(2);
                        }else {
                            //未知状态
                            transResult.setTransStatus(0);
                            subjectInThirdBills.setStatus(0);
                        }
                    } else {
                        transResult.setMsg(platformErrorMessage);
                        subjectInThirdBills.setStatus(2);
                        transResult.setTransStatus(2);
                    }
                }else {
                    transResult.setMsg(ErrorMsg.RETURN_DATA_CHECK_SIGN_FAIL);
                }
            }else {
                transResult.setMsg(ErrorMsg.PAY_INTERFACE_RETURN_BLANK);
            }
        }

        try {
            subjectInThirdBillsService.insert(subjectInThirdBills);
        } catch (Exception e) {
            log.error("畅捷代扣插入第三方订单表异常,billNo:{},error:{}",request.getBillNo(),e);
        }

        return transResult;
    }


    @Override
    public String deductNotify(ChangpayCallbackRequest request) {
        String result ="";

        //记录回调原始数据
        SubjectInNotifyLog subjectInNotifyLog = new SubjectInNotifyLog();
        subjectInNotifyLog.setBillNo(request.getOuter_trade_no());
        subjectInNotifyLog.setCallbackText(JSONObject.toJSONString(request));
        //默认回调处理状态为处理中
        subjectInNotifyLog.setStatus(0);
        //默认订单交易状态为处理中
        subjectInNotifyLog.setTransStatus(0);
        subjectInNotifyLog.setCallbackText(JSONObject.toJSONString(request));
        subjectInNotifyLog.setMsg("回调处理中");
        boolean rt = subjectInNotifyLogService.insert(subjectInNotifyLog);
        if (!rt){
            log.error("插入回调日志表失败,request:{}",request);
            return result;
        }

        //查询回调对应的订单信息
        SubjectInBills subjectInBillsFind = new SubjectInBills();
        subjectInBillsFind.setBillNo(request.getOuter_trade_no());
        SubjectInBills subjectInBills = subjectInBillsService.getLastOneInBills(subjectInBillsFind);
        if(null==subjectInBills){
            log.error("未查询到该笔订单,request:{}",request);
            return result;
        }
        subjectInNotifyLog.setSubjectCode(subjectInBills.getSubjectCode());
        subjectInNotifyLog.setMerchantBillNo(subjectInBills.getMerchantBillNo());

        //转发到支付中台的回调对象
        NotifyRequest notifyRequest=new NotifyRequest();
        notifyRequest.setMerchantBillNo(subjectInBills.getMerchantBillNo());
        notifyRequest.setBillNo(subjectInBills.getBillNo());
        notifyRequest.setTransStatus(0);
        notifyRequest.setMsg("回调处理中");
        notifyRequest.setTransTime(System.currentTimeMillis());
        notifyRequest.setAmount(subjectInBills.getAmount());

        String category=subjectInBills.getChannelCode();
        String publicKey=subjectChannelConfigService.getConfigString(category,ConfigKeyEnums.PUBLICKEY.getName());

        boolean verifyResult = false;
        if(null!=request){
            //签名
            String sign=request.getSign();
            String sign2=null;
            try {
                Map<String,String> maps = (Map) JSON.parse(subjectInNotifyLog.getCallbackText());
                maps = ChanPayUtil.paraFilter(maps);
                if(!maps.containsKey("_input_charset")){
                    maps.put("_input_charset","UTF-8");
                }
                sign2= ChanPayUtil.createLinkString(maps,false);
                verifyResult=RSA.verify(sign2,sign,publicKey, BaseConstant.CHARSET);
            } catch (Exception e) {
                log.error("畅捷支付代扣回调返回数据签名出错,request:{},error:{}",request,e);
            }

            if(verifyResult){
                String transNo=request.getInner_trade_no();
                //WITHDRAWAL_SUCCESS:成功  WITHDRAWAL_FAIL：失败 RETURN_TICKET：退票
                String status=request.getTrade_status();
                //支付时间 要转换 yyyyMMddHHmmss
                String tradeTime=request.getGmt_payment();
                //失败原因
                String fail_reason=request.getFail_reason();

                subjectInNotifyLog.setStatus(1);
                subjectInNotifyLog.setTransNo(transNo);
                subjectInNotifyLog.setMsg(fail_reason);
                notifyRequest.setTransNo(transNo);
                notifyRequest.setMsg(fail_reason);

                if ((subjectInBills.getStatus().intValue() == 0 || subjectInBills.getStatus().intValue() == 3)){
                    if(StringUtils.isNotBlank(status)){
                        if(StringUtils.equals("TRADE_SUCCESS",status) || StringUtils.equals("TRADE_FINISHED",status)){
                            //支付成功
                            if(StringUtils.isNotBlank(tradeTime)){
                                Long time= DateUtils.convert(tradeTime,DateUtils.DATE_TIMESTAMP_SHORT_FORMAT).getTime();
                                notifyRequest.setTransTime(time);
                            }else{
                                notifyRequest.setTransTime(System.currentTimeMillis());
                            }

                            notifyRequest.setTransStatus(1);
                            subjectInNotifyLog.setTransStatus(1);
                        }else if(StringUtils.equals("TRADE_CLOSED",status)){
                            //支付失败
                            notifyRequest.setTransStatus(2);
                            subjectInNotifyLog.setTransStatus(2);
                        } else {
                            //支付处理中
                            notifyRequest.setTransStatus(0);
                            subjectInNotifyLog.setTransStatus(0);
                        }
                    }else {
                        subjectInNotifyLog.setMsg("没有交易状态");
                    }

                    int transStatus = notifyRequest.getTransStatus().intValue();
                    if (transStatus == 1 || transStatus == 2) {
                        //更新订单表状态
                        subjectInBills.setStatus(transStatus);
                        subjectInBillsService.updateById(subjectInBills);
                        try {
                            //TODO 回调支付中台
                            subjectPayNotifyUtil.notifyPay(subjectInBills.getSubjectCode(),"notify/deduct",notifyRequest);
                        }catch (Exception e){
                            log.error("回调支付中台异常，notifyRequest：{},error：{}",notifyRequest,e);
                        }
                    }
                }else {
                    subjectInNotifyLog.setMsg("订单状态已确定,不处理");
                }
                result ="success";
            }else {
                //验签不通过
                //直接返回不处理业务
                subjectInNotifyLog.setStatus(2);
                subjectInNotifyLog.setMsg("畅捷支付回调_验签不通过");
                log.error("畅捷支付回调_验签失败,request:{}",request);
            }

        }

        //记录通知第三方支付公司的信息
        subjectInNotifyLog.setResponseText(result);
        try {
            subjectInNotifyLogService.updateById(subjectInNotifyLog);
        }catch (Exception e){
            log.error("更新支付回调记录表失败,request:{},error:{}",request,e);
        }
        return result;
    }

    @Override
    public TransResult firstProtocolPayApply(TransRequest request) {
        TransResult transResult = new TransResult();
        transResult.setBillNo(request.getBillNo());
        transResult.setMerchantBillNo(request.getMerchantBillNo());
        transResult.setAmount(request.getAmount());
        transResult.setTransStatus(0);
        transResult.setTransTime(System.currentTimeMillis());

        String category=request.getChannelCode().getCode();

        String merchantNo=subjectChannelConfigService.getConfigString(category,ConfigKeyEnums.MERCHANTNO.getName());
        String requestUrl=subjectChannelConfigService.getConfigString(category,ConfigKeyEnums.REQUESTURL.getName());
        String privateKey=subjectChannelConfigService.getConfigString(category,ConfigKeyEnums.PRIVATEKEY.getName());
        String publicKey=subjectChannelConfigService.getConfigString(category,ConfigKeyEnums.PUBLICKEY.getName());
        String callBackUrl=subjectChannelConfigService.getConfigString(category,ConfigKeyEnums.CALLBACKURL.getName());
        String MD5Key=subjectChannelConfigService.getConfigString(category,ConfigKeyEnums.MD5KEY.getName());

        if(StringUtils.isBlank(requestUrl) || StringUtils.isBlank(merchantNo) || StringUtils.isBlank(privateKey) || StringUtils.isBlank(publicKey) || StringUtils.isBlank(callBackUrl) || StringUtils.isBlank(MD5Key)){
            transResult.setTransStatus(2);
            transResult.setMsg(ErrorMsg.INCOMPLETE_CONFIG_INFO);
            return transResult;
        }

        Map<String,String>  map = this.requestBaseParameter("nmg_zft_api_quick_payment",merchantNo);
        // 商户网站唯一订单号
        map.put("TrxId",request.getBillNo());
        // 商品名称
        map.put("OrdrName","用户还款");
        // 商户网站用户唯一标识
        map.put("MerUserId",request.getIdCard());
        // 调用畅捷子账户开通接口获取的子账户编号; 该字段可以传入平台id或者平台id下的子账户号;作为收款方使用，与鉴权接口中MerchantNO保持一致
        map.put("SellerId",merchantNo);
        // 在畅捷商户自助平台申请开通的子商户，用于自动结算
        map.put("SubMerchantNo","");
        // 订单有效期 取值范围：1m～48h。单位为分，如1.5h，可转换为90m。如果超过该有效期进行确认则提示订单已超时。不允许确认。
        map.put("ExpiredTime","30m");
        // 卡类型（00 –银行贷记卡;01 –银行借记卡;）
        map.put("BkAcctTp","01");
        // 卡号
        map.put("BkAcctNo",ChanPayUtil.encrypt(request.getCardNo(),publicKey, BaseConstant.CHARSET));
        // 证件类型 01：身份证
        map.put("IDTp","01");
        // 证件号
        map.put("IDNo", ChanPayUtil.encrypt(request.getIdCard(), publicKey, BaseConstant.CHARSET));
        //持卡人姓名
        map.put("CstmrNm",ChanPayUtil.encrypt(request.getName(), publicKey, BaseConstant.CHARSET));
        //银行预留手机号
        map.put("MobNo",ChanPayUtil.encrypt(request.getPhone(), publicKey, BaseConstant.CHARSET));
        //交易类型（即时 11 担保 12）
        map.put("TradeType","11");
        //交易金额（单位:元）
        map.put("TrxAmt",request.getAmount().toString());
        //异步通知地址
        map.put("NotifyUrl",callBackUrl);

        MultiValueMap<String, String> postParameters = new LinkedMultiValueMap<String, String>();
        try {
            Map<String, String> param = ChanPayUtil.buildRequestPara(map,"RSA", privateKey, BaseConstant.CHARSET);
            for(String key : param.keySet()) {
                String value = URLEncoder.encode(param.get(key), BaseConstant.CHARSET);
                postParameters.add(key, value);
            }
        } catch (Exception e) {
            log.error("畅捷协议首次支付请求请求数据加密失败,billNo:{},error:{}",request.getBillNo(),e);
            transResult.setTransStatus(2);
            transResult.setMsg(ErrorMsg.DATA_ENCRYPTION_FAIL);
            return transResult;
        }

        SubjectInThirdBills subjectInThirdBills=new SubjectInThirdBills();
        subjectInThirdBills.setSubjectCode(request.getSubjectCode());
        subjectInThirdBills.setMerchantBillNo(request.getMerchantBillNo());
        subjectInThirdBills.setBillNo(request.getBillNo());
        subjectInThirdBills.setStatus(0);
        subjectInThirdBills.setAmount(request.getAmount());
        subjectInThirdBills.setRequestUrl(requestUrl);
        subjectInThirdBills.setRequestText(JSON.toJSONString(postParameters));
        subjectInThirdBills.setBeginTime(System.currentTimeMillis());
        subjectInThirdBills.setServiceType(request.getServiceType());

        String str = null;
        try {
            str = restTemplate.postForObject(requestUrl,postParameters,String.class);
        } catch (Exception e) {
            log.error("调用畅捷协议首次支付请求接口异常,billNo:{},error:{}",request.getBillNo(),e);
            transResult.setMsg(ErrorMsg.PAY_INTERFACE_CALL_FAIL);
        }

        subjectInThirdBills.setResponseText((StringUtils.isNotBlank(str) && str.length()>4000)?str.substring(0,4000):str);
        subjectInThirdBills.setEndTime(System.currentTimeMillis());

        if (StringUtils.isBlank(str)) {
            //默认交易处理中
            log.error("调用畅捷协议首次支付请求接口返回空,billNo:{}",request.getBillNo());
            transResult.setMsg(ErrorMsg.PAY_INTERFACE_RETURN_BLANK);
        }else {
            JSONObject jsonObjectStr = JSONObject.parseObject(str);
            if(null != jsonObjectStr){
                //签名
                String sign=jsonObjectStr.getString("Sign");
                String sign2=null;
                boolean verifyResult=false;
                try {
                    Map<String,String> maps = (Map) JSON.parse(str);
                    sign2=ChanPayUtil.createLinkString(maps,false);
                    verifyResult= RSA.verify(sign2,sign,publicKey,BaseConstant.CHARSET);
                } catch (Exception e) {
                    transResult.setMsg(ErrorMsg.RETURN_DATA_CHECK_SIGN_FAIL);
                    log.error("畅捷协议首次支付请求返回数据签名出错,str:{},error:{}",str,e);
                }
                if(verifyResult){
                    //请求状态 S：受理成功 F：受理失败 表示接口调用是否成功，并不表明业务处理结果
                    String acceptStatus=jsonObjectStr.getString("AcceptStatus");
                    //业务状态:S成功 F失败 P 处理中
                    String status=jsonObjectStr.getString("Status");
                    //畅捷流水号
                    String flowNo=jsonObjectStr.getString("OrderTrxId");
                    //返回描述
                    String msg=jsonObjectStr.getString("RetMsg");

                    transResult.setTransNo(flowNo);
                    transResult.setMsg(msg);

                    if (StringUtils.equals(acceptStatus,"S")) {
                        if(StringUtils.equals(status,"S")){
                            //交易成功
                            transResult.setTransTime(System.currentTimeMillis());
                            transResult.setTransStatus(1);
                            subjectInThirdBills.setStatus(1);
                        } else if(StringUtils.equals(status,"F")){
                            //交易失败
                            transResult.setTransStatus(2);
                            subjectInThirdBills.setStatus(2);
                        }else {
                            //未知状态（因为是申请，可能发了验证码，特殊处理，设置成成功）
                            transResult.setTransStatus(1);
                            subjectInThirdBills.setStatus(1);
                        }
                    } else {
                        transResult.setTransStatus(2);
                        subjectInThirdBills.setStatus(2);
                    }
                }else {
                    transResult.setMsg(ErrorMsg.RETURN_DATA_CHECK_SIGN_FAIL);
                }
            }else {
                transResult.setMsg(ErrorMsg.PAY_INTERFACE_RETURN_BLANK);
            }
        }

        try {
            subjectInThirdBillsService.insert(subjectInThirdBills);
        } catch (Exception e) {
            log.error("畅捷插入第三方订单表异常,billNo:{},error:{}",request.getBillNo(),e);
        }

        return transResult;
    }

    @Override
    public TransResult firstProtocolPayConfirm(TransRequest request) {
        TransResult transResult = new TransResult();
        transResult.setBillNo(request.getBillNo());
        transResult.setMerchantBillNo(request.getMerchantBillNo());
        transResult.setAmount(request.getAmount());
        transResult.setTransStatus(0);
        transResult.setTransTime(System.currentTimeMillis());

        String category=request.getChannelCode().getCode();

        String merchantNo=subjectChannelConfigService.getConfigString(category,ConfigKeyEnums.MERCHANTNO.getName());
        String requestUrl=subjectChannelConfigService.getConfigString(category,ConfigKeyEnums.REQUESTURL.getName());
        String privateKey=subjectChannelConfigService.getConfigString(category,ConfigKeyEnums.PRIVATEKEY.getName());
        String publicKey=subjectChannelConfigService.getConfigString(category,ConfigKeyEnums.PUBLICKEY.getName());
        String callBackUrl=subjectChannelConfigService.getConfigString(category,ConfigKeyEnums.CALLBACKURL.getName());
        String MD5Key=subjectChannelConfigService.getConfigString(category,ConfigKeyEnums.MD5KEY.getName());

        if(StringUtils.isBlank(requestUrl) || StringUtils.isBlank(merchantNo) || StringUtils.isBlank(privateKey) || StringUtils.isBlank(publicKey) || StringUtils.isBlank(callBackUrl) || StringUtils.isBlank(MD5Key)){
            transResult.setTransStatus(2);
            transResult.setMsg(ErrorMsg.INCOMPLETE_CONFIG_INFO);
            return transResult;
        }

        Map<String,String>  map = this.requestBaseParameter("nmg_api_quick_payment_smsconfirm",merchantNo);
        String TrxId = UUID.randomUUID().toString().replaceAll("-","");
        // 商户网站唯一订单号
        map.put("TrxId",TrxId);
        // 原支付请求订单号
        map.put("OriPayTrxId",request.getBillNo());
        // 确认支付短信验证码
        map.put("SmsCode",request.getSmsCode());

        MultiValueMap<String, String> postParameters = new LinkedMultiValueMap<String, String>();
        try {
            Map<String, String> param = ChanPayUtil.buildRequestPara(map,"RSA", privateKey, BaseConstant.CHARSET);
            for(String key : param.keySet()) {
                String value = URLEncoder.encode(param.get(key), BaseConstant.CHARSET);
                postParameters.add(key, value);
            }
        } catch (Exception e) {
            log.error("畅捷协议首次支付确认请求数据加密失败,billNo:{},error:{}",request.getBillNo(),e);
            transResult.setTransStatus(2);
            transResult.setMsg(ErrorMsg.DATA_ENCRYPTION_FAIL);
            return transResult;
        }

        SubjectInThirdBills subjectInThirdBills=new SubjectInThirdBills();
        subjectInThirdBills.setSubjectCode(request.getSubjectCode());
        subjectInThirdBills.setMerchantBillNo(request.getMerchantBillNo());
        subjectInThirdBills.setBillNo(request.getBillNo());
        subjectInThirdBills.setStatus(0);
        subjectInThirdBills.setAmount(request.getAmount());
        subjectInThirdBills.setRequestUrl(requestUrl);
        subjectInThirdBills.setRequestText(JSON.toJSONString(postParameters));
        subjectInThirdBills.setBeginTime(System.currentTimeMillis());
        subjectInThirdBills.setServiceType(request.getServiceType());

        String str = null;
        try {
            str = restTemplate.postForObject(requestUrl,postParameters,String.class);
        } catch (Exception e) {
            log.error("调用畅捷协议首次支付确认接口异常,billNo:{},error:{}",request.getBillNo(),e);
            transResult.setMsg(ErrorMsg.PAY_INTERFACE_CALL_FAIL);
        }

        subjectInThirdBills.setResponseText((StringUtils.isNotBlank(str) && str.length()>4000)?str.substring(0,4000):str);
        subjectInThirdBills.setEndTime(System.currentTimeMillis());

        if (StringUtils.isBlank(str)) {
            //默认交易处理中
            log.error("调用畅捷协议首次支付确认接口返回空,billNo:{}",request.getBillNo());
            transResult.setMsg(ErrorMsg.PAY_INTERFACE_RETURN_BLANK);
        }else {
            JSONObject jsonObjectStr = JSONObject.parseObject(str);
            if(null != jsonObjectStr){
                //签名
                String sign=jsonObjectStr.getString("Sign");
                String sign2=null;
                boolean verifyResult=false;
                try {
                    Map<String,String> maps = (Map) JSON.parse(str);
                    sign2=ChanPayUtil.createLinkString(maps,false);
                    verifyResult= RSA.verify(sign2,sign,publicKey,BaseConstant.CHARSET);
                } catch (Exception e) {
                    transResult.setMsg(ErrorMsg.RETURN_DATA_CHECK_SIGN_FAIL);
                    log.error("畅捷协议首次支付确认返回数据签名出错,str:{},error:{}",str,e);
                }
                if(verifyResult){
                    //请求状态 S：受理成功 F：受理失败 表示接口调用是否成功，并不表明业务处理结果
                    String acceptStatus=jsonObjectStr.getString("AcceptStatus");
                    //业务状态:S成功 F失败 P 处理中
                    String status=jsonObjectStr.getString("Status");
                    //畅捷流水号
                    String flowNo=jsonObjectStr.getString("OrderTrxId");
                    //返回描述
                    String msg=jsonObjectStr.getString("RetMsg");

                    transResult.setTransNo(flowNo);
                    transResult.setMsg(msg);

                    if (StringUtils.equals(acceptStatus,"S")) {
                        if(StringUtils.equals(status,"S")){
                            //交易成功
                            transResult.setTransTime(System.currentTimeMillis());
                            transResult.setTransStatus(1);
                            subjectInThirdBills.setStatus(1);

                            //TODO 确认绑卡成功，存起来
                            //TODO 对于这种首次支付成功就算绑卡成功的协议支付渠道，在确认支付接口及支付结果回调通知接口都要存下用户绑卡标识
                            ThirdProtocolApply thirdProtocolApply=new ThirdProtocolApply();
                            thirdProtocolApply.setSubjectCode(request.getSubjectCode());
                            thirdProtocolApply.setChannelCode(request.getChannelCode().getCode());
                            thirdProtocolApply.setMerchantBillNo(request.getMerchantBillNo());
                            thirdProtocolApply.setBillNo(request.getBillNo());
                            String protocolNo=bindCardService.saveProtocolNo(thirdProtocolApply);
                            //TODO 还要通知支付中台
                            if(StringUtils.isNotBlank(protocolNo)){
                                transResult.setProtocolNo(protocolNo);
                            }

                        } else if(StringUtils.equals(status,"F")){
                            //交易失败
                            transResult.setTransStatus(2);
                            subjectInThirdBills.setStatus(2);
                        }else {
                            //未知状态
                            transResult.setTransStatus(0);
                            subjectInThirdBills.setStatus(0);
                        }
                    } else {
                        transResult.setTransStatus(2);
                        subjectInThirdBills.setStatus(2);
                    }
                }else {
                    transResult.setMsg(ErrorMsg.RETURN_DATA_CHECK_SIGN_FAIL);
                }
            }else {
                transResult.setMsg(ErrorMsg.PAY_INTERFACE_RETURN_BLANK);
            }
        }

        try {
            subjectInThirdBillsService.insert(subjectInThirdBills);
        } catch (Exception e) {
            log.error("畅捷插入第三方订单表异常,billNo:{},error:{}",request.getBillNo(),e);
        }

        return transResult;
    }

    @Override
    public TransResult firstProtocolPayReSendSMS(TransRequest request) {
        TransResult transResult = new TransResult();
        transResult.setBillNo(request.getBillNo());
        transResult.setMerchantBillNo(request.getMerchantBillNo());
        transResult.setAmount(request.getAmount());
        transResult.setTransStatus(0);
        transResult.setTransTime(System.currentTimeMillis());

        String category=request.getChannelCode().getCode();

        String merchantNo=subjectChannelConfigService.getConfigString(category,ConfigKeyEnums.MERCHANTNO.getName());
        String requestUrl=subjectChannelConfigService.getConfigString(category,ConfigKeyEnums.REQUESTURL.getName());
        String privateKey=subjectChannelConfigService.getConfigString(category,ConfigKeyEnums.PRIVATEKEY.getName());
        String publicKey=subjectChannelConfigService.getConfigString(category,ConfigKeyEnums.PUBLICKEY.getName());
        String callBackUrl=subjectChannelConfigService.getConfigString(category,ConfigKeyEnums.CALLBACKURL.getName());
        String MD5Key=subjectChannelConfigService.getConfigString(category,ConfigKeyEnums.MD5KEY.getName());

        if(StringUtils.isBlank(requestUrl) || StringUtils.isBlank(merchantNo) || StringUtils.isBlank(privateKey) || StringUtils.isBlank(publicKey) || StringUtils.isBlank(callBackUrl) || StringUtils.isBlank(MD5Key)){
            transResult.setTransStatus(2);
            transResult.setMsg(ErrorMsg.INCOMPLETE_CONFIG_INFO);
            return transResult;
        }

        Map<String,String>  map = this.requestBaseParameter("nmg_api_quick_payment_resend",merchantNo);
        String TrxId = UUID.randomUUID().toString().replaceAll("-","");
        // 商户网站唯一订单号
        map.put("TrxId",TrxId);
        // 原支付请求订单号
        map.put("OriTrxId",request.getBillNo());
        //原业务订单类型   鉴权订单：auth_order 支付订单；pay _order
        map.put("TradeType","pay_order");

        MultiValueMap<String, String> postParameters = new LinkedMultiValueMap<String, String>();
        try {
            Map<String, String> param = ChanPayUtil.buildRequestPara(map,"RSA", privateKey, BaseConstant.CHARSET);
            for(String key : param.keySet()) {
                String value = URLEncoder.encode(param.get(key), BaseConstant.CHARSET);
                postParameters.add(key, value);
            }
        } catch (Exception e) {
            log.error("畅捷协议首次支付重发短信验证码请求数据加密失败,billNo:{},error:{}",request.getBillNo(),e);
            transResult.setTransStatus(2);
            transResult.setMsg(ErrorMsg.DATA_ENCRYPTION_FAIL);
            return transResult;
        }

        SubjectInThirdBills subjectInThirdBills=new SubjectInThirdBills();
        subjectInThirdBills.setSubjectCode(request.getSubjectCode());
        subjectInThirdBills.setMerchantBillNo(request.getMerchantBillNo());
        subjectInThirdBills.setBillNo(request.getBillNo());
        subjectInThirdBills.setStatus(0);
        subjectInThirdBills.setAmount(request.getAmount());
        subjectInThirdBills.setRequestUrl(requestUrl);
        subjectInThirdBills.setRequestText(JSON.toJSONString(postParameters));
        subjectInThirdBills.setBeginTime(System.currentTimeMillis());
        subjectInThirdBills.setServiceType(request.getServiceType());

        String str = null;
        try {
            str = restTemplate.postForObject(requestUrl,postParameters,String.class);
        } catch (Exception e) {
            log.error("调用畅捷协议首次支付重发短信验证码请求接口异常,billNo:{},error:{}",request.getBillNo(),e);
            transResult.setMsg(ErrorMsg.PAY_INTERFACE_CALL_FAIL);
        }

        subjectInThirdBills.setResponseText((StringUtils.isNotBlank(str) && str.length()>4000)?str.substring(0,4000):str);
        subjectInThirdBills.setEndTime(System.currentTimeMillis());

        if (StringUtils.isBlank(str)) {
            //默认交易处理中
            log.error("调用畅捷协议首次支付重发短信验证码请求接口返回空,billNo:{}",request.getBillNo());
            transResult.setMsg(ErrorMsg.PAY_INTERFACE_RETURN_BLANK);
        }else {
            JSONObject jsonObjectStr = JSONObject.parseObject(str);
            if(null != jsonObjectStr){
                //签名
                String sign=jsonObjectStr.getString("Sign");
                String sign2=null;
                boolean verifyResult=false;
                try {
                    Map<String,String> maps = (Map) JSON.parse(str);
                    sign2=ChanPayUtil.createLinkString(maps,false);
                    verifyResult= RSA.verify(sign2,sign,publicKey,BaseConstant.CHARSET);
                } catch (Exception e) {
                    transResult.setMsg(ErrorMsg.RETURN_DATA_CHECK_SIGN_FAIL);
                    log.error("畅捷协议首次支付重发短信验证码请求返回数据签名出错,str:{},error:{}",str,e);
                }
                if(verifyResult){
                    //请求状态 S：受理成功 F：受理失败 表示接口调用是否成功，并不表明业务处理结果
                    String acceptStatus=jsonObjectStr.getString("AcceptStatus");
                    //业务状态:S成功 F失败 P 处理中
                    String status=jsonObjectStr.getString("Status");
                    //畅捷流水号
                    String flowNo=jsonObjectStr.getString("OrderTrxId");
                    //返回描述
                    String msg=jsonObjectStr.getString("RetMsg");

                    transResult.setTransNo(flowNo);
                    transResult.setMsg(msg);

                    if (StringUtils.equals(acceptStatus,"S")) {
                        if(StringUtils.equals(status,"S")){
                            //交易成功
                            transResult.setTransTime(System.currentTimeMillis());
                            transResult.setTransStatus(1);
                            subjectInThirdBills.setStatus(1);
                        } else if(StringUtils.equals(status,"F")){
                            //交易失败
                            transResult.setTransStatus(2);
                            subjectInThirdBills.setStatus(2);
                        }else {
                            //未知状态
                            transResult.setTransStatus(0);
                            subjectInThirdBills.setStatus(0);
                        }
                    } else {
                        transResult.setTransStatus(2);
                        subjectInThirdBills.setStatus(2);
                    }
                }else {
                    transResult.setMsg(ErrorMsg.RETURN_DATA_CHECK_SIGN_FAIL);
                }
            }else {
                transResult.setMsg(ErrorMsg.PAY_INTERFACE_RETURN_BLANK);
            }
        }

        try {
            subjectInThirdBillsService.insert(subjectInThirdBills);
        } catch (Exception e) {
            log.error("畅捷插入第三方订单表异常,billNo:{},error:{}",request.getBillNo(),e);
        }

        return transResult;
    }

    @Override
    public TransResult secondProtocolPay(TransRequest request) {
        TransResult transResult = new TransResult();
        transResult.setBillNo(request.getBillNo());
        transResult.setMerchantBillNo(request.getMerchantBillNo());
        transResult.setAmount(request.getAmount());
        transResult.setTransStatus(0);
        transResult.setTransTime(System.currentTimeMillis());

        String category=request.getChannelCode().getCode();

        String merchantNo=subjectChannelConfigService.getConfigString(category,ConfigKeyEnums.MERCHANTNO.getName());
        String requestUrl=subjectChannelConfigService.getConfigString(category,ConfigKeyEnums.REQUESTURL.getName());
        String privateKey=subjectChannelConfigService.getConfigString(category,ConfigKeyEnums.PRIVATEKEY.getName());
        String publicKey=subjectChannelConfigService.getConfigString(category,ConfigKeyEnums.PUBLICKEY.getName());
        String callBackUrl=subjectChannelConfigService.getConfigString(category,ConfigKeyEnums.CALLBACKURL.getName());
        String MD5Key=subjectChannelConfigService.getConfigString(category,ConfigKeyEnums.MD5KEY.getName());

        if(StringUtils.isBlank(requestUrl) || StringUtils.isBlank(merchantNo) || StringUtils.isBlank(privateKey) || StringUtils.isBlank(publicKey) || StringUtils.isBlank(callBackUrl) || StringUtils.isBlank(MD5Key)){
            transResult.setTransStatus(2);
            transResult.setMsg(ErrorMsg.INCOMPLETE_CONFIG_INFO);
            return transResult;
        }

        Map<String,String>  map = this.requestBaseParameter("nmg_biz_api_quick_payment",merchantNo);
        // 商户网站唯一订单号
        map.put("TrxId",request.getBillNo());
        // 商品名称
        map.put("OrdrName","用户还款");
        // 商户网站用户唯一标识
        map.put("MerUserId",request.getIdCard());
        // 调用畅捷子账户开通接口获取的子账户编号; 该字段可以传入平台id或者平台id下的子账户号;作为收款方使用，与鉴权接口中MerchantNO保持一致
        map.put("SellerId",merchantNo);
        // 在畅捷商户自助平台申请开通的子商户，用于自动结算
        map.put("SubMerchantNo","");
        // 订单有效期 取值范围：1m～48h。单位为分，如1.5h，可转换为90m。如果超过该有效期进行确认则提示订单已超时。不允许确认。
        map.put("ExpiredTime","30m");
        //交易类型（即时 11 担保 12）
        map.put("TradeType","11");
        //卡号前6位
        map.put("CardBegin",request.getCardNo().substring(0,6));
        //卡号后4位
        map.put("CardEnd",request.getCardNo().substring(request.getCardNo().length()-4));
        //交易金额（单位:元）
        map.put("TrxAmt",request.getAmount().toString());
        //异步通知地址
        map.put("NotifyUrl",callBackUrl);
        //短信发送标识 0：不发送短信 1：发送短信
        map.put("SmsFlag","0");

        MultiValueMap<String, String> postParameters = new LinkedMultiValueMap<String, String>();
        try {
            Map<String, String> param = ChanPayUtil.buildRequestPara(map,"RSA", privateKey, BaseConstant.CHARSET);
            for(String key : param.keySet()) {
                String value = URLEncoder.encode(param.get(key), BaseConstant.CHARSET);
                postParameters.add(key, value);
            }
        } catch (Exception e) {
            log.error("畅捷协议二次支付请求数据加密失败,billNo:{},error:{}",request.getBillNo(),e);
            transResult.setTransStatus(2);
            transResult.setMsg(ErrorMsg.DATA_ENCRYPTION_FAIL);
            return transResult;
        }

        SubjectInThirdBills subjectInThirdBills=new SubjectInThirdBills();
        subjectInThirdBills.setSubjectCode(request.getSubjectCode());
        subjectInThirdBills.setMerchantBillNo(request.getMerchantBillNo());
        subjectInThirdBills.setBillNo(request.getBillNo());
        subjectInThirdBills.setStatus(0);
        subjectInThirdBills.setAmount(request.getAmount());
        subjectInThirdBills.setRequestUrl(requestUrl);
        subjectInThirdBills.setRequestText(JSON.toJSONString(postParameters));
        subjectInThirdBills.setBeginTime(System.currentTimeMillis());
        subjectInThirdBills.setServiceType(request.getServiceType());

        String str = null;
        try {
            str = restTemplate.postForObject(requestUrl,postParameters,String.class);
        } catch (Exception e) {
            log.error("调用畅捷协议二次支付请求接口异常,billNo:{},error:{}",request.getBillNo(),e);
            transResult.setMsg(ErrorMsg.PAY_INTERFACE_CALL_FAIL);
        }

        subjectInThirdBills.setResponseText((StringUtils.isNotBlank(str) && str.length()>4000)?str.substring(0,4000):str);
        subjectInThirdBills.setEndTime(System.currentTimeMillis());

        if (StringUtils.isBlank(str)) {
            //默认交易处理中
            log.error("调用畅捷协议二次支付请求接口返回空,billNo:{}",request.getBillNo());
            transResult.setMsg(ErrorMsg.PAY_INTERFACE_RETURN_BLANK);
        }else {
            JSONObject jsonObjectStr = JSONObject.parseObject(str);
            if(null != jsonObjectStr){
                //签名
                String sign=jsonObjectStr.getString("Sign");
                String sign2=null;
                boolean verifyResult=false;
                try {
                    Map<String,String> maps = (Map) JSON.parse(str);
                    sign2=ChanPayUtil.createLinkString(maps,false);
                    verifyResult= RSA.verify(sign2,sign,publicKey,BaseConstant.CHARSET);
                } catch (Exception e) {
                    transResult.setMsg(ErrorMsg.RETURN_DATA_CHECK_SIGN_FAIL);
                    log.error("畅捷协议二次支付请求返回数据签名出错,str:{},error:{}",str,e);
                }
                if(verifyResult){
                    //请求状态 S：受理成功 F：受理失败 表示接口调用是否成功，并不表明业务处理结果
                    String acceptStatus=jsonObjectStr.getString("AcceptStatus");
                    //业务状态:S成功 F失败 P 处理中
                    String status=jsonObjectStr.getString("Status");
                    //畅捷流水号
                    String flowNo=jsonObjectStr.getString("OrderTrxId");
                    //返回描述
                    String msg=jsonObjectStr.getString("RetMsg");

                    transResult.setTransNo(flowNo);
                    transResult.setMsg(msg);

                    if (StringUtils.equals(acceptStatus,"S")) {
                        if(StringUtils.equals(status,"S")){
                            //交易成功
                            transResult.setTransTime(System.currentTimeMillis());
                            transResult.setTransStatus(1);
                            subjectInThirdBills.setStatus(1);
                        } else if(StringUtils.equals(status,"F")){
                            //交易失败
                            transResult.setTransStatus(2);
                            subjectInThirdBills.setStatus(2);
                        }else {
                            //未知状态
                            transResult.setTransStatus(0);
                            subjectInThirdBills.setStatus(0);
                        }
                    } else {
                        transResult.setTransStatus(2);
                        subjectInThirdBills.setStatus(2);
                    }
                }else {
                    transResult.setMsg(ErrorMsg.RETURN_DATA_CHECK_SIGN_FAIL);
                }
            }else {
                transResult.setMsg(ErrorMsg.PAY_INTERFACE_RETURN_BLANK);
            }
        }

        try {
            subjectInThirdBillsService.insert(subjectInThirdBills);
        } catch (Exception e) {
            log.error("畅捷插入第三方订单表异常,billNo:{},error:{}",request.getBillNo(),e);
        }

        return transResult;
    }

    @Override
    public TransResult protocolPayQuery(SubjectpayQueryRequest request) {
        TransResult transResult = new TransResult();
        transResult.setBillNo(request.getBillNo());
        transResult.setMerchantBillNo(request.getMerchantBillNo());
        transResult.setAmount(request.getAmount());
        transResult.setTransStatus(0);
        transResult.setTransTime(System.currentTimeMillis());

        String category=request.getChannelCode();

        String merchantNo=subjectChannelConfigService.getConfigString(category,ConfigKeyEnums.MERCHANTNO.getName());
        String requestUrl=subjectChannelConfigService.getConfigString(category,ConfigKeyEnums.REQUESTURL.getName());
        String privateKey=subjectChannelConfigService.getConfigString(category,ConfigKeyEnums.PRIVATEKEY.getName());
        String publicKey=subjectChannelConfigService.getConfigString(category,ConfigKeyEnums.PUBLICKEY.getName());
        String callBackUrl=subjectChannelConfigService.getConfigString(category,ConfigKeyEnums.CALLBACKURL.getName());
        String MD5Key=subjectChannelConfigService.getConfigString(category,ConfigKeyEnums.MD5KEY.getName());

        if(StringUtils.isBlank(requestUrl) || StringUtils.isBlank(merchantNo) || StringUtils.isBlank(privateKey) || StringUtils.isBlank(publicKey) || StringUtils.isBlank(callBackUrl) || StringUtils.isBlank(MD5Key)){
            transResult.setTransStatus(2);
            transResult.setMsg(ErrorMsg.INCOMPLETE_CONFIG_INFO);
            return transResult;
        }

        Map<String, String> map = this.requestBaseParameter("cjt_dsf",merchantNo);
        String TrxId = UUID.randomUUID().toString().replaceAll("-","");
        // 商户网站唯一订单号
        map.put("TrxId",TrxId);
        // 原业务订单号
        map.put("OrderTrxId",request.getBillNo());
        // 原业务订单类型 auth_order：鉴权订单 pay_order   ：支付订单refund_order：退款订单
        map.put("TradeType","pay_order");

        SubjectInThirdBills subjectInThirdBills=new SubjectInThirdBills();
        subjectInThirdBills.setSubjectCode(request.getSubjectCode());
        subjectInThirdBills.setMerchantBillNo(request.getMerchantBillNo());
        subjectInThirdBills.setBillNo(request.getBillNo());
        subjectInThirdBills.setStatus(0);
        subjectInThirdBills.setAmount(request.getAmount());
        subjectInThirdBills.setRequestUrl(requestUrl);
        subjectInThirdBills.setRequestText(JSON.toJSONString(map));
        subjectInThirdBills.setBeginTime(System.currentTimeMillis());
        subjectInThirdBills.setServiceType(request.getServiceType());

        MultiValueMap<String, String> postParameters = new LinkedMultiValueMap<String, String>();
        try {
            Map<String, String> param = ChanPayUtil.buildRequestPara(map,"RSA", privateKey, BaseConstant.CHARSET);
            for(String key : param.keySet()) {
                String value = URLEncoder.encode(param.get(key), BaseConstant.CHARSET);
                postParameters.add(key, value);
            }
        } catch (Exception e) {
            log.error("畅捷协议支付查询请求数据加密失败,billNo:{},error:{}",request.getBillNo(),e);
            transResult.setTransStatus(2);
            transResult.setMsg(ErrorMsg.DATA_ENCRYPTION_FAIL);
            return transResult;
        }

        String str = null;
        try {
            str = restTemplate.postForObject(requestUrl,postParameters,String.class);
        } catch (Exception e) {
            log.error("调用畅捷协议支付查询接口异常,billNo:{},error:{}",request.getBillNo(),e);
            transResult.setMsg(ErrorMsg.PAY_INTERFACE_CALL_FAIL);
        }

        subjectInThirdBills.setResponseText((StringUtils.isNotBlank(str) && str.length()>4000)?str.substring(0,4000):str);
        subjectInThirdBills.setEndTime(System.currentTimeMillis());

        if (StringUtils.isBlank(str)) {
            //默认交易处理中
            log.error("调用畅捷支付协议支付查询接口返回空,billNo:{}",request.getBillNo());
            transResult.setMsg(ErrorMsg.PAY_INTERFACE_RETURN_BLANK);
        }else {
            JSONObject jsonObjectStr = JSONObject.parseObject(str);
            if(null != jsonObjectStr){
                //签名
                String sign=jsonObjectStr.getString("Sign");
                String sign2=null;
                boolean verifyResult=false;
                try {
                    Map<String,String> maps = (Map) JSON.parse(str);
                    sign2=ChanPayUtil.createLinkString(maps,false);
                    verifyResult= RSA.verify(sign2,sign,publicKey,BaseConstant.CHARSET);
                } catch (Exception e) {
                    transResult.setMsg(ErrorMsg.RETURN_DATA_CHECK_SIGN_FAIL);
                    log.error("畅捷支付协议支付查询返回数据签名出错,str:{},error:{}",str,e);
                }
                if(verifyResult){
                    //请求状态 S：受理成功 F：受理失败 表示接口调用是否成功，并不表明业务处理结果
                    String acceptStatus=jsonObjectStr.getString("AcceptStatus");
                    //业务状态:S成功 F失败 P 处理中
                    String status=jsonObjectStr.getString("Status");
                    //畅捷流水号
                    String flowNo=jsonObjectStr.getString("OrderTrxId");
                    //返回描述
                    String msg=jsonObjectStr.getString("RetMsg");

                    transResult.setTransNo(flowNo);
                    transResult.setMsg(msg);

                    if (StringUtils.equals(acceptStatus,"S")) {
                        if(StringUtils.equals(status,"S")){
                            //交易成功
                            transResult.setTransTime(System.currentTimeMillis());
                            transResult.setTransStatus(1);
                            subjectInThirdBills.setStatus(1);

                            //TODO 确认绑卡成功，存起来
                            //TODO 对于这种首次支付成功就算绑卡成功的协议支付渠道，在确认支付接口及支付结果回调通知接口都要存下用户绑卡标识
                            ThirdProtocolApply thirdProtocolApply=new ThirdProtocolApply();
                            thirdProtocolApply.setSubjectCode(request.getSubjectCode());
                            thirdProtocolApply.setChannelCode(request.getChannelCode());
                            thirdProtocolApply.setMerchantBillNo(request.getMerchantBillNo());
                            thirdProtocolApply.setBillNo(request.getBillNo());
                            String protocolNo=bindCardService.saveProtocolNo(thirdProtocolApply);
                            //TODO 还要通知支付中台
                            if(StringUtils.isNotBlank(protocolNo)){
                                transResult.setProtocolNo(protocolNo);
                            }

                        } else if(StringUtils.equals(status,"F")){
                            //交易失败
                            transResult.setTransStatus(2);
                            subjectInThirdBills.setStatus(2);
                        }else {
                            //未知状态
                            transResult.setTransStatus(0);
                            subjectInThirdBills.setStatus(0);
                        }
                    } else {
                        transResult.setTransStatus(2);
                        subjectInThirdBills.setStatus(2);
                    }

                }else {
                    transResult.setMsg(ErrorMsg.RETURN_DATA_CHECK_SIGN_FAIL);
                }
            }else {
                transResult.setMsg(ErrorMsg.PAY_INTERFACE_RETURN_BLANK);
            }
        }

        try {
            subjectInThirdBillsService.insert(subjectInThirdBills);
        } catch (Exception e) {
            log.error("畅捷代扣插入第三方订单表异常,billNo:{},error:{}",request.getBillNo(),e);
        }

        return transResult;
    }


    @Override
    public String protocolPayNotify(ChangpayCallbackRequest request) {
        String result ="";

        //记录回调原始数据
        SubjectInNotifyLog subjectInNotifyLog = new SubjectInNotifyLog();
        subjectInNotifyLog.setBillNo(request.getOuter_trade_no());
        subjectInNotifyLog.setCallbackText(JSONObject.toJSONString(request));
        //默认回调处理状态为处理中
        subjectInNotifyLog.setStatus(0);
        //默认订单交易状态为处理中
        subjectInNotifyLog.setTransStatus(0);
        subjectInNotifyLog.setCallbackText(JSONObject.toJSONString(request));
        subjectInNotifyLog.setMsg("回调处理中");
        boolean rt = subjectInNotifyLogService.insert(subjectInNotifyLog);
        if (!rt){
            log.error("插入回调日志表失败,request:{}",request);
            return result;
        }

        //查询回调对应的订单信息
        SubjectInBills subjectInBillsFind = new SubjectInBills();
        subjectInBillsFind.setBillNo(request.getOuter_trade_no());
        SubjectInBills subjectInBills = subjectInBillsService.getLastOneInBills(subjectInBillsFind);
        if(null==subjectInBills){
            log.error("未查询到该笔订单,request:{}",request);
            return result;
        }
        subjectInNotifyLog.setSubjectCode(subjectInBills.getSubjectCode());
        subjectInNotifyLog.setMerchantBillNo(subjectInBills.getMerchantBillNo());

        //转发到支付中台的回调对象
        NotifyRequest notifyRequest=new NotifyRequest();
        notifyRequest.setMerchantBillNo(subjectInBills.getMerchantBillNo());
        notifyRequest.setBillNo(subjectInBills.getBillNo());
        notifyRequest.setTransStatus(0);
        notifyRequest.setMsg("回调处理中");
        notifyRequest.setTransTime(System.currentTimeMillis());
        notifyRequest.setAmount(subjectInBills.getAmount());

        String category=subjectInBills.getChannelCode();
        String publicKey=subjectChannelConfigService.getConfigString(category,ConfigKeyEnums.PUBLICKEY.getName());

        boolean verifyResult = false;
        if(null!=request){
            //签名
            String sign=request.getSign();
            String sign2=null;
            try {
                Map<String,String> maps = (Map) JSON.parse(subjectInNotifyLog.getCallbackText());
                maps = ChanPayUtil.paraFilter(maps);
                if(!maps.containsKey("_input_charset")){
                    maps.put("_input_charset","UTF-8");
                }
                sign2= ChanPayUtil.createLinkString(maps,false);
                verifyResult=RSA.verify(sign2,sign,publicKey, BaseConstant.CHARSET);
            } catch (Exception e) {
                log.error("畅捷协议支付回调返回数据签名出错,request:{},error:{}",request,e);
            }

            if(verifyResult){
                String transNo=request.getInner_trade_no();
                //WITHDRAWAL_SUCCESS:成功  WITHDRAWAL_FAIL：失败 RETURN_TICKET：退票
                String status=request.getTrade_status();
                //支付时间 要转换 yyyyMMddHHmmss
                String tradeTime=request.getGmt_payment();
                //失败原因
                String fail_reason=request.getFail_reason();

                subjectInNotifyLog.setStatus(1);
                subjectInNotifyLog.setTransNo(transNo);
                subjectInNotifyLog.setMsg(fail_reason);
                notifyRequest.setTransNo(transNo);
                notifyRequest.setMsg(fail_reason);

                if ((subjectInBills.getStatus().intValue() == 0 || subjectInBills.getStatus().intValue() == 3)){
                    if(StringUtils.isNotBlank(status)){
                        if(StringUtils.equals("TRADE_SUCCESS",status) || StringUtils.equals("TRADE_FINISHED",status)){
                            //支付成功
                            if(StringUtils.isNotBlank(tradeTime)){
                                Long time= DateUtils.convert(tradeTime,DateUtils.DATE_TIMESTAMP_SHORT_FORMAT).getTime();
                                notifyRequest.setTransTime(time);
                            }else{
                                notifyRequest.setTransTime(System.currentTimeMillis());
                            }

                            notifyRequest.setTransStatus(1);
                            subjectInNotifyLog.setTransStatus(1);

                            //TODO 确认绑卡成功，存起来
                            //TODO 对于这种首次支付成功就算绑卡成功的协议支付渠道，在确认支付接口及支付结果回调通知接口都要存下用户绑卡标识
                            ThirdProtocolApply thirdProtocolApply=new ThirdProtocolApply();
                            thirdProtocolApply.setSubjectCode(subjectInBills.getSubjectCode());
                            thirdProtocolApply.setChannelCode(subjectInBills.getChannelCode());
                            thirdProtocolApply.setMerchantBillNo(subjectInBills.getMerchantBillNo());
                            thirdProtocolApply.setBillNo(subjectInBills.getBillNo());
                            String protocolNo=bindCardService.saveProtocolNo(thirdProtocolApply);
                            //TODO 还要通知支付中台
                            if(StringUtils.isNotBlank(protocolNo)){
                                notifyRequest.setProtocolNo(protocolNo);
                            }

                        }else if(StringUtils.equals("TRADE_CLOSED",status) || StringUtils.equals("PAY_FAIL",status)){
                            //支付失败
                            notifyRequest.setTransStatus(2);
                            subjectInNotifyLog.setTransStatus(2);
                        } else {
                            //支付处理中
                            notifyRequest.setTransStatus(0);
                            subjectInNotifyLog.setTransStatus(0);
                        }
                    }else {
                        subjectInNotifyLog.setMsg("没有交易状态");
                    }

                    int transStatus = notifyRequest.getTransStatus().intValue();
                    if (transStatus == 1 || transStatus == 2) {
                        //更新订单表状态
                        subjectInBills.setStatus(transStatus);
                        subjectInBillsService.updateById(subjectInBills);
                        try {
                            //TODO 回调支付中台
                            subjectPayNotifyUtil.notifyPay(subjectInBills.getSubjectCode(),"notify/protocolPay",notifyRequest);
                        }catch (Exception e){
                            log.error("回调支付中台异常，notifyRequest：{},error：{}",notifyRequest,e);
                        }
                    }
                }else {
                    subjectInNotifyLog.setMsg("订单状态已确定,不处理");
                }
                result ="success";
            }else {
                //验签不通过
                //直接返回不处理业务
                subjectInNotifyLog.setStatus(2);
                subjectInNotifyLog.setMsg("畅捷支付回调_验签不通过");
                log.error("畅捷协议支付回调_验签失败,request:{}",request);
            }

        }

        //记录通知第三方支付公司的信息
        subjectInNotifyLog.setResponseText(result);
        try {
            subjectInNotifyLogService.updateById(subjectInNotifyLog);
        }catch (Exception e){
            log.error("更新支付回调记录表失败,request:{},error:{}",request,e);
        }
        return result;
    }

    /**
     * 获取基本的请求业务参数
     * @param service
     * @param partnerId
     * @return
     */
    public Map<String,String> requestBaseParameter(String service, String partnerId){
        Map<String, String> origMap = new HashMap<String, String>();
        // 2.1 基本参数
        //服务名
        origMap.put(BaseConstant.SERVICE, service);
        origMap.put(BaseConstant.VERSION, "1.0");
        // 畅捷支付分配的商户号
        origMap.put(BaseConstant.PARTNER_ID, partnerId);
        origMap.put(BaseConstant.TRADE_DATE, BaseConstant.DATE);
        origMap.put(BaseConstant.TRADE_TIME, BaseConstant.TIME);
        // 字符集
        origMap.put(BaseConstant.INPUT_CHARSET, BaseConstant.CHARSET);
        // 备注
        origMap.put(BaseConstant.MEMO, "放款/扣款");
        return origMap;
    }

}

